#include <string>
#include <vector>
#include "task.hpp"

enum Usage
{
    UsageError = 1,
    ArgError
};

class Channel
{
public:
    Channel(int wfd, pid_t sub_id, string name)
        : _wfd(wfd), _sub_process_id(sub_id), _name(name)
    {
    }
    int wfd() { return _wfd; }
    ~Channel()
    {
    }

private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
        : _sub_process_num(sub_process_num)
    {
    }
    int CreateProcess(work_t work) // 回调函数
    {
        for (int number = 0; number < _sub_process_num; number++)
        {
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            pid_t id = fork();

            // 子进程 -> r
            if (id == 0)
            {
                close(pipefd[1]);
                // 执行
                dup2(pipefd[0], 0);
                work();
                exit(0);
            }
            string channle_name = "channel-" + to_string(number);
            // 父进程 -> w
            close(pipefd[0]);
            _channels.push_back(Channel(pipefd[1], id, channle_name));
        }
        return 0;
    }
    int NextChannel() // 轮询
    {
        static int next = 0;
        int cur = next;
        next++;
        next %= _channels.size();
        return cur;
    }
    void SendTaskCode(int index, uint32_t code)
    {
        write(_channels[index].wfd(), &code, sizeof(code));
    }
    ~ProcessPool() {}

private:
    vector<Channel> _channels;
    int _sub_process_num;
};

int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = stoi(argv[1]);
    if(sub_process_num<=0)
    {
        return ArgError;
    }
    ProcessPool processpool(sub_process_num);
    processpool.CreateProcess(worker);
    while(1)
    {
        // a. 选择一个进程和通道
        int cur = processpool.NextChannel();
        // b. 选择一个任务
        uint32_t code = NextTask();
        // c. 发送任务
        processpool.SendTaskCode(cur,code);
    }
    return 0;
}